设计模式之原型模式 您所在的位置:网站首页 golang 原型模式 设计模式之原型模式

设计模式之原型模式

#设计模式之原型模式| 来源: 网络整理| 查看: 265

设计模式之原型模式 1.克隆羊问题

现在有一只羊 tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和 tom羊属性完全相同的 5只羊。

传统方式

1.1 绘制UML类图

image-20200920214301948

1.2编写代码 public class Sheep { private Integer age; private String name; private String color; public Sheep(Integer age, String name, String color) { this.age = age; this.name = name; this.color = color; } //因为篇幅限制,这里省略getter和setter、有参构造方法以及toString的编写 } public class Client { public static void main(String[] args) { Sheep sheep = new Sheep(1, "tom", "白色"); Sheep sheep1 = new Sheep(sheep.getAge(), sheep.getName(), sheep.getColor()); Sheep sheep2 = new Sheep(sheep.getAge(), sheep.getName(), sheep.getColor()); Sheep sheep3 = new Sheep(sheep.getAge(), sheep.getName(), sheep.getColor()); Sheep sheep4 = new Sheep(sheep.getAge(), sheep.getName(), sheep.getColor()); System.out.println(sheep); System.out.println(sheep1); System.out.println(sheep2); System.out.println(sheep3); System.out.println(sheep4); } }

image-20200920214703863

1.3优缺点 优点是比较好理解,简单易操作。 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象比较复杂时,效率较低 总是需要重新初始化对象,而不是动态地获得对象运行时的状态, 不够灵活

改进的思路分析:

​ 思路:Java 中 Object 类是所有类的根类,Object 类提供了一个 clone()方法,该方法可以将一个 Java 对象复制一份,但是需要实现

clone 的 Java 类必须要实现一个接口 Cloneable,该接口表示该类能够复制且具有复制的能力 =>原型模式

2.原型模式 2.1 概述 原型模式是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道创建的细节。 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone() 2.2 绘制UML类图

image-20200921075102380

UML类图说明:

Protptype:抽象原型类,实现Cloneable接口,也就是我们用户使用复制粘贴的功能。

ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作,说明一下它有被克隆复制的功能。

Client:客户类提出创建对象的请求。

2.3 代码编写 //prototype抽象原型类 public abstract class Sheep implements Cloneable{ private Integer age; private String name; private String color; private Sheep friend;//如果成员变量为对象,默认为浅拷贝 public Sheep(Integer age, String name, String color) { this.age = age; this.name = name; this.color = color; } //重写clone方法 @Override protected Sheep clone() throws CloneNotSupportedException { Sheep sheep =null; try { sheep = (Sheep) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return sheep; } //具体原型角色ConcretePrototype public class ConcretePrototype extends Sheep { public ConcretePrototype(Integer age, String name, String color) { super(age, name, color); } } //Client public class Client { public static void main(String[] args) throws CloneNotSupportedException { ConcretePrototype concretePrototype = new ConcretePrototype(20,"汤姆","蓝色"); concretePrototype.setFriend(new Sheep(21,"朋友","白色")); ConcretePrototype clone = (ConcretePrototype) concretePrototype.clone(); ConcretePrototype clone1 = (ConcretePrototype) concretePrototype.clone(); ConcretePrototype clone2 = (ConcretePrototype) concretePrototype.clone(); ConcretePrototype clone3 = (ConcretePrototype) concretePrototype.clone(); System.out.println(concretePrototype+"@@@"+concretePrototype.hashCode()+"@@@"+concretePrototype.getFriend().hashCode()); System.out.println(clone+"@@@"+clone.hashCode()+"@@@"+clone.getFriend().hashCode()); System.out.println(clone1+"@@@"+clone1.hashCode()+"@@@"+clone1.getFriend().hashCode()); System.out.println(clone2+"@@@"+clone2.hashCode()+"@@@"+clone2.getFriend().hashCode()); System.out.println(clone3+"@@@"+clone3.hashCode()+"@@@"+clone3.getFriend().hashCode()); } }

image-20200921085436835

我们可以看到,克隆出来的对象属性与之前的文件属性是一样的,但两个对象的HashCode是不一样的,也就是说创建了新的对象。

但是ConcretePrototype内的friend对象拷贝的是引用。因为Object.clone()方法默认是浅拷贝。

3.浅拷贝与深拷贝 浅拷贝

对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。

对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是

将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在

一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

我们上述案例就是浅拷贝,浅拷贝是使用默认的clone()方法来实现

深拷贝

复制对象的所有基本数据类型的成员变量值

为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就

是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝。

实现方式:

重写clone方法来实现深拷贝

2. 通过对象序列化方式实现深拷贝(推荐) public class A implements Cloneable, Serializable { //必须显式重写 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Sheep implements Cloneable,Serializable{ private Integer age; private String name; private String color; private A a;//如果成员变量为对象,默认为浅拷贝 public Sheep(Integer age, String name, String color) { this.age = age; this.name = name; this.color = color; } //方式一:重写clone方法 @Override protected Object clone() throws CloneNotSupportedException { Sheep sheep =null; try { //这里完成对基本数据类型和String的拷贝 sheep = (Sheep) super.clone(); //对引用类型的属性,进行单独处理 A a1 = (A) a.clone(); sheep.setA(a1); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return sheep; } //方式二:通过对象的序列化方式实现(推荐) public Object deepClone(){ //创建流对象 ByteArrayOutputStream bos =null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; Sheep obj = null; try { //序列化 bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); //将当前这个对象以对象流的方式输出 oos.writeObject(this); //反序列化 bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis); obj = (Sheep)ois.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if(bos!=null){ bos.close(); } if(oos!=null){ oos.close(); } if(bis!=null){ bis.close(); } if(ois!=null){ ois.close(); } } catch (IOException e) { e.printStackTrace(); } } return obj; } //省略getter、setter和toString } public class ConcretePrototype extends Sheep implements Cloneable , Serializable { public ConcretePrototype(Integer age, String name, String color) { super(age, name, color); } } public class Client { public static void main(String[] args) throws CloneNotSupportedException { //方式一:重写clone方法 /*ConcretePrototype concretePrototype = new ConcretePrototype(20,"汤姆","蓝色"); concretePrototype.setA(new A()); ConcretePrototype clone = (ConcretePrototype) concretePrototype.clone(); ConcretePrototype clone1 = (ConcretePrototype) concretePrototype.clone(); ConcretePrototype clone2 = (ConcretePrototype) concretePrototype.clone(); ConcretePrototype clone3 = (ConcretePrototype) concretePrototype.clone(); System.out.println(concretePrototype+"@@@"+concretePrototype.hashCode()); System.out.println(clone+"@@@"+clone.hashCode()); System.out.println(clone1+"@@@"+clone1.hashCode()); System.out.println(clone2+"@@@"+clone2.hashCode()); System.out.println(clone3+"@@@"+clone3.hashCode());*/ //方式二:序列化 ConcretePrototype concretePrototype = new ConcretePrototype(20,"汤姆","蓝色"); concretePrototype.setA(new A()); ConcretePrototype clone = (ConcretePrototype) concretePrototype.deepClone(); ConcretePrototype clone1 = (ConcretePrototype) concretePrototype.deepClone(); ConcretePrototype clone2 = (ConcretePrototype) concretePrototype.deepClone(); ConcretePrototype clone3 = (ConcretePrototype) concretePrototype.deepClone(); System.out.println(concretePrototype+"@@@"+concretePrototype.hashCode()); System.out.println(clone+"@@@"+clone.hashCode()); System.out.println(clone1+"@@@"+clone1.hashCode()); System.out.println(clone2+"@@@"+clone2.hashCode()); System.out.println(clone3+"@@@"+clone3.hashCode()); } }

运行结果:

方式一:

image-20200921102451165

方式二:

image-20200921105301691

注意:

A类,Sheep类,ConcretePrototype类都需要实现Cloneable和Serializable接口 需要显式重写A类的clone方法,因为Object中的clone方法是protected修饰的,而protected修饰的方法只允许同包下的类和子类访问,Sheep类就调用不了A的clone方法,所以必须显示重写A类的方法。 4.注意事项

创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率

不用重新初始化对象,而是动态地获得对象运行时的状态

如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码

在实现深克隆的时候可能需要比较复杂的代码

缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则,



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有